/* test_mutex_func_uthread_mutex_unlock():
	A test for uthread_mutex_unlock(). Checks the regular case + the error
	cases.

	Does:
	* Creates additional thread: 1.

	1)
	* Checks for MUTEX_INVALID error.
	* Checks for MUTEX_UNINITIALIZED error.

	2)
	* thread 0 initilize mutex_a.
	* thread 1 unlocks mutex_a (MUTEX_UNLOCKED)
	* thread 0 locks mutex_a twise.
	* thread 1 unlocks mutex_a (MUTEX_LOCKED).
	* thread 0 unlocks mutex_a twise (success).
	* thread 1 unlocks mutex_a (MUTEX_UNLOCKED)
*/


#include <stdio.h>
#include <stdbool.h>

#include "test_general.h"
#include "user_threads.h"
#include "user_mutex.h"


bool test_mutex_func_uthread_mutex_unlock();


#define THREADS_NUM 2


uthread_mutex_t mutex_a;


static int thread1_start_routine(void * param) {
	TEST_ASSERT (uthread_self() == 1);


	int tmp = uthread_mutex_unlock(mutex_a);
	TEST_ASSERT(MUTEX_UNLOCKED == tmp);

	some_long_operation(0.1);
	// thread 0 locked mutex_a.

	tmp = uthread_mutex_unlock(mutex_a);
	TEST_ASSERT(MUTEX_LOCKED == tmp);

	some_long_operation(0.2);
	// thread 0 unlocks mutex_a.

	tmp = uthread_mutex_unlock(mutex_a);
		TEST_ASSERT(MUTEX_UNLOCKED == tmp);

	tmp = uthread_mutex_destroy(mutex_a);
	TEST_ASSERT(tmp == MUTEX_SUCCESS);

	thread_ok[1] = true;
	return 0;
}


bool test_mutex_func_uthread_mutex_unlock()
{
	init_individual_test();

	int tmp;

	if (initilize_uthread_in_each_test) {
		tmp = uthread_init();
		TEST_ASSERT(tmp == UTHREAD_SUCCESS);
	}


	/* Checking for MUTEX_INVALID,MUTEX_UNINITIALIZED: */
	tmp = uthread_mutex_unlock(NULL);
	TEST_ASSERT (MUTEX_INVALID == tmp);
	tmp = uthread_mutex_unlock((uthread_mutex_t)&tmp);
	TEST_ASSERT (MUTEX_UNINITIALIZED == tmp);


	tmp = uthread_mutex_init(&mutex_a);
	TEST_ASSERT(tmp == MUTEX_SUCCESS);

	thread_id threads[THREADS_NUM];

	threads[0] = uthread_self();
	TEST_ASSERT(threads[0] == 0);

	int FiftyThree = 53;

	threads[1] = uthread_create(thread1_start_routine, &FiftyThree);
	TEST_ASSERT(threads[1] == 1);

	uthread_yield();

	tmp = uthread_mutex_lock(mutex_a);
	TEST_ASSERT(tmp == MUTEX_SUCCESS);
	/*tmp = uthread_mutex_lock(mutex_a);
	TEST_ASSERT(tmp == MUTEX_SUCCESS); */


	some_long_operation(0.2);

	tmp = uthread_mutex_unlock(mutex_a);
	TEST_ASSERT(tmp == MUTEX_SUCCESS);
	tmp = uthread_mutex_unlock(mutex_a);
	TEST_ASSERT(tmp == MUTEX_UNLOCKED); 

	tmp = uthread_join(1,NULL);
	TEST_ASSERT(tmp == UTHREAD_SUCCESS);

	thread_ok[0] = true;
	TEST_ASSERT(are_all_threads_ok(THREADS_NUM));

	return true;
}

